package org.hive.managers.plugin
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundMixer;
	import flash.media.SoundTransform;
	import flash.system.Capabilities;
	import flash.utils.Dictionary;
	import org.hive.sequence.Sequence;
	
	import caurina.transitions.Tweener;
	
	import org.hive.data.SoundData;
	import org.hive.managers.*;
	
	public class SoundManager extends Manager
	{	
		
		public static var initialized:Boolean = false;
		
		//_________________________________________________________________________________________________ REGISTER CONTROLLER
		public static function init():void
		{
			if( !initialized ) {
				trace( "SoundManager :: initializing" );
				
				//_____________ Register Object :: SoundData
				function conditionalFunction( action:*, sequence:Sequence, positionInSequence:int ):void {
					SoundData(action).playSound();
				}
				StateManager.registerAction(SoundData, conditionalFunction);
				
				//_____________ Register Object :: SoundData : Tweener
				function tweenableConditionalFunction( action:*, sequence:Sequence, positionInSequence:int ):void {
					var scope:SoundData = SoundData(action.scope);
					delete action.scope;
					
					if ( scope.soundChannel.position == 0 )
						scope.playSound();
						
					Tweener.addTween( scope.soundChannel, action );
				}
				StateManager.registerAction(SoundData, tweenableConditionalFunction, true);
				
				// Loader Element Distribution
				if ( !LoadManager.initialized ) LoadManager.init();
				function loaderElementFunction( loaderElement:* ):void {
					SoundManager.add( loaderElement );
				}
				LoadManager.registerLoaderElement(SoundData, loaderElementFunction);
				
				
				__SOUNDS 			= new Dictionary( true );
				__SOUNDS_BY_NAME	= new Dictionary( true );
				__SOUND_TRANSFORM 	= new SoundTransform();
				SoundMixer.soundTransform = __SOUND_TRANSFORM;
				__currentVolume = __SOUND_TRANSFORM.volume;
				
				initialized = true;
			}
		}
		
		
		
		//_________________________________________________________________________________________________ MODEL
		private static var __SOUNDS				:Dictionary;
		private static var __SOUNDS_BY_NAME		:Dictionary;
		private static var __SOUND_TRANSFORM 	:SoundTransform;
		
		public static function add( ...args ):void
		{
			for (var i:Number = 0; i < args.length; i++) {
				__SOUNDS_BY_NAME[ args[i].name ] = args[i];
				__SOUNDS[ args[i] ] = args[i].name;
		    }
		}
		
		public static function remove( sound:* ):void
		{
			delete __SOUNDS[ sound ];
			delete __SOUNDS_BY_NAME[ sound.name ];
		}
		
		public static function removeByName( ...names ):void
		{
			for (var i:Number = 0; i < names.length; i++) {
		        remove( getSoundByName( names[i] ) )
		    }
		}
		
		public static function getSoundByName( name:String ):SoundData
		{
			return __SOUNDS_BY_NAME[ name ];
		}
		
		
		
		
		
		//_________________________________________________________________________________________________ VIEW
		private static var __currentVolume	:int; 
		
		public static function set volume( num:Number ):void
		{
			__SOUND_TRANSFORM.volume = __currentVolume = num;
			SoundMixer.soundTransform = __SOUND_TRANSFORM;
		}
		
		public static function set pan( num:Number ):void
		{
			__SOUND_TRANSFORM.pan = num;
			SoundMixer.soundTransform = __SOUND_TRANSFORM;
		}
		
		public static function mute( p_fade:Boolean=true ):void
		{	
			__currentVolume = __SOUND_TRANSFORM.volume;
			
			if( p_fade )
				Tweener.addTween( __SOUND_TRANSFORM, { volume:0, time:1, onUpdate:fadeSound } );
			else
				__SOUND_TRANSFORM.volume = 0;
		}
		
		public static function unmute( p_fade:Boolean=true ):void
		{		
			if( p_fade )
				Tweener.addTween( __SOUND_TRANSFORM, { volume:__currentVolume, time:1, onUpdate:fadeSound } );
			else
				__SOUND_TRANSFORM.volume = __currentVolume;
		}
		
		private static function fadeSound( ):void
		{
			SoundMixer.soundTransform = __SOUND_TRANSFORM;
		}
		
		public static function get hasAudio():Boolean {
			return Capabilities.hasAudio;
		}
		
		
		//_________________________________________________________________________________________________ STATIC EVENT DISPATCHER METHODS
		protected static var disp:EventDispatcher;
		
		public static function addEventListener(p_type:String, p_listener:Function, p_useCapture:Boolean = false, p_priority:int = 0, p_useWeakReference:Boolean = false):void {
			if (disp == null) { disp = new EventDispatcher(); }
			disp.addEventListener(p_type, p_listener, p_useCapture, p_priority, p_useWeakReference);
		}
		
		public static function removeEventListener(p_type:String, p_listener:Function, p_useCapture:Boolean=false):void {
			if (disp == null) { return; }
			disp.removeEventListener(p_type, p_listener, p_useCapture);
		}
		
		public static function dispatchEvent(p_event:Event):void {
			if (disp == null) { return; }
			disp.dispatchEvent(p_event);
		}
		
		
	}
}